/*
** Xin YUAN, 2023, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////

#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>

#include "base/_x_thread_pool.h"

////////////////////////////////////////////////////////////////////////////////

inline uint32_t get_processor_number() noexcept
{
	int num = (int)::sysconf(_SC_NPROCESSORS_ONLN);
	return num < 1 ? 1 : num;
}

struct _epoll_server_data_header
{
	enum { TYPE_EVENT = 0, TYPE_SOCKET, TYPE_TIMER };
	int type;
};

struct _epoll_server_data_full : public _epoll_server_data_header
{
	void* pv;

	_epoll_server_data_header* get_header() noexcept
	{
		return static_cast<_epoll_server_data_header*>(this);
	}
};

//handle_server_data_base

class handle_server_data_base : public handle_data_base
{
private:
	volatile int iCloseFlag;
	volatile int iNextFlag;
	volatile int iCallFlag;

	int iCurrentFlag;
	int tmfd;

	_epoll_server_data_full socket_data;
	_epoll_server_data_full timer_data;

protected:
	handle_server_data_base() noexcept : iCloseFlag(0), iNextFlag(0), iCallFlag(0), tmfd(-1)
	{
		socket_data.type = _epoll_server_data_header::TYPE_SOCKET;
		socket_data.pv = this;
		timer_data.type = _epoll_server_data_header::TYPE_TIMER;
		timer_data.pv = this;
	}
	handle_server_data_base(const handle_server_data_base&) = delete;
	~handle_server_data_base() noexcept
	{
		close_timer();
	}
	handle_server_data_base& operator=(const handle_server_data_base&) = delete;

private:
	bool is_valid_timer() const noexcept
	{
		return tmfd != -1;
	}
	bool init_timer() noexcept
	{
		if ( tmfd == -1 ) {
			tmfd = ::timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK);
			if ( tmfd == -1 ) //errno
				return false;
		}
		return true;
	}
	void close_timer() noexcept
	{
		if ( tmfd != -1 ) {
			int ret = ::close(tmfd);
			(void)ret;
			assert( ret == 0 );  //-1, errno
			tmfd = -1;
		}
	}

private:
	friend class server_base;
};

//server_base

class server_base
{
protected:
	typedef server_util  utilClass;

private:
	enum { e_listen = 0, e_in, e_out, e_inout };

	struct thread_item
	{
		void* pv;
		pthread_t tid;
		int epfd;  //epoll
		int evtfd;

		_epoll_server_data_header evt_data { _epoll_server_data_header::TYPE_EVENT };
	};

protected:
	server_base() noexcept : m_iExit(0), m_iFinish(0), m_uCurrentTurn(0)
	{
	}
	server_base(const server_base&) = delete;
	~server_base() noexcept
	{
		assert( !is_valid() );
	}

	server_base& operator=(const server_base&) = delete;

protected:
	bool init(utilClass::server_callback cb, uint32_t tm) noexcept
	{
		assert( !is_valid() );
		//callback
		m_util.callback = cb;
		//timeout
		m_util.init_timeout(tm);
		//thread pool
		uint32_t uNum = get_processor_number() * 2;
		if ( uNum > _POOL_MAX_THREAD_NUM / 2 ) {
			uNum /= 2;
			if ( uNum > _POOL_MAX_THREAD_NUM / 2 )
				uNum = _POOL_MAX_THREAD_NUM / 2;
		}
		if ( !m_arrPool.SetSize(uNum) )
			return false;
		for ( uint32_t i = 0; i < uNum; i ++ ) {
			if ( !init_thread(m_arrPool[i], this) ) {
				dump_thread_pool_size(i);
				m_arrPool.Clear();
				return false;
			}
		}
		return true;
	}

public:
	//Do not reuse handle_server_data_base in used list after calling this method
	//  If this object has listen socket, 60s must be waited for next listen after this method calling.
	void Shutdown() noexcept
	{
		if ( is_valid() ) {
			//dump thread pool
			dump_thread_pool();
			m_arrPool.Clear();
		}
	}

	bool StartListen(handle_server_data_base* p, uint32_t port) noexcept
	{
		if ( __sync_val_compare_and_swap(&m_iExit, 1, 1) )
			return true;
		//addr
		struct sockaddr_storage ss;
		socklen_t len;
		if ( !_x_socket_helper::FillSockAddr(ss, len, AF_INET, port) )
			return false;
		//socket
		ns_socket sock;
		if ( !sock.GetSocket().Create(AF_INET, SOCK_STREAM) )
			return false;
		if ( !sock.GetSocket().Bind((struct sockaddr*)&ss, len) )
			return false;
		if ( !sock.GetSocket().Listen() )
			return false;
		//timer
		if ( !p->init_timer() )
			return false;
		//epoll
		p->sock = rv_forward(sock);
		p->op_type = OP_TYPE_ACCEPT;
		p->iCloseFlag = 0;
		thread_item& item = m_arrPool[fetch_current_turn()];
		p->index = (uintptr_t)(&item);
		if ( !epoll_rev_event(item.epfd, p->tmfd, p->timer_data.get_header(), true) ) {
			p->sock.GetSocket().Close();
			p->op_type = OP_TYPE_NONE;
			return false;
		}
		if ( !epoll_rev_socket(item.epfd, p, e_listen, true) ) {
			epoll_del_timer(item.epfd, p);  //no check
			p->sock.GetSocket().Close();
			p->op_type = OP_TYPE_NONE;
			return false;
		}
		return true;
	}
	bool StartConnect(handle_server_data_base* p, const char_s* host, uint32_t port) noexcept
	{
		if ( __sync_val_compare_and_swap(&m_iExit, 1, 1) )
			return true;
		//addr
		struct sockaddr_storage ss;
		socklen_t len;
		if ( !host_to_sockaddr(host, port, ss, len) )
			return false;
		//socket
		ns_socket sock;
		if ( !sock.GetSocket().Create(AF_INET, SOCK_STREAM) )
			return false;
		if ( !sock.GetSocket().Connect((struct sockaddr*)&ss, len) ) {
			if ( errno != EINPROGRESS && errno != EAGAIN )
				return false;
		}
		//timer
		if ( !p->init_timer() )
			return false;
		//to epoll
		p->sock = rv_forward(sock);
		p->op_type = OP_TYPE_CONNECT;
		p->send_len = p->act_sent_len = 0;
		p->iCloseFlag = 0;
		thread_item& item = m_arrPool[fetch_current_turn()];
		p->index = (uintptr_t)(&item);
		if ( !epoll_rev_event(item.epfd, p->tmfd, p->timer_data.get_header(), true) ) {
			p->sock.GetSocket().Close();
			p->op_type = OP_TYPE_NONE;
			return false;
		}
		if ( !epoll_rev_socket(item.epfd, p, e_out, true) ) {
			epoll_del_timer(item.epfd, p);  //no check
			p->sock.GetSocket().Close();
			p->op_type = OP_TYPE_NONE;
			return false;
		}
		return true;
	}

protected:
	bool _BeginInput(handle_server_data_base* p, uint32_t uSendLength) noexcept
	{
		assert( uSendLength > 0 && uSendLength <= HANDLE_BUFFER_SIZE );
		//acquire
		while ( __sync_val_compare_and_swap(&(p->iCallFlag), 0, 1) )
			;
		//check
		if ( __sync_val_compare_and_swap(&m_iExit, 1, 1) )
			return true;
		if ( __sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1) )
			return true;
		if ( __sync_val_compare_and_swap(&(p->send_len), 0, uSendLength) ) {
			__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
			return false;
		}
		return true;
	}
	bool _EndInput(handle_server_data_base* p) noexcept
	{
		if ( __sync_val_compare_and_swap(&m_iExit, 1, 1) ) {
			__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
			return true;
		}
		if ( __sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1) ) {
			__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
			return true;
		}
		assert( p->send_len != 0 );
		if ( p->op_type != OP_TYPE_USER )
			start_next(p);
		__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
		return true;
	}

	//This method must be called in DoSent() using its input parameter p before the next _StartInput() calling.
	static void _FinishSend(handle_server_data_base* p) noexcept
	{
		p->act_sent_len = 0;
		uint32_t len = p->send_len;
		__sync_sub_and_fetch(&(p->send_len), len);
	}

	bool _MarkClose(handle_server_data_base* p) noexcept
	{
		//acquire
		while ( __sync_val_compare_and_swap(&(p->iCallFlag), 0, 1) )
			;
		//process
		if ( !__sync_val_compare_and_swap(&(p->iCloseFlag), 0, 1) ) {
			if ( p->op_type != OP_TYPE_USER )
				start_next(p);
		}
		//finish
		__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
		return true;
	}

private:
	static void* worker_thread(void* p) noexcept
	{
		thread_item* pItem = (thread_item*)p;
		server_base* pThis = (server_base*)(pItem->pv);
		//events
		struct epoll_event events[1024];
		handle_server_data_base* next_array[1024];
		uint32_t next_count;
		//notify
		__sync_val_compare_and_swap(&pThis->m_iFinish, 0, 1);
		//loop
		while ( true ) {
			//epoll
			int ret = ::epoll_wait(pItem->epfd, events, (int)(sizeof(events) / sizeof(struct epoll_event)), -1);  //block
			if ( ret == -1 ) {
				if ( errno == EINTR )
					continue;
				//sleep
				thread_sleep(1);  //1ms
				continue;
			}
			bool brev = true;
			(void)brev;
			bool exit_flag = false;
			next_count = 0;
			for ( int i = 0; i < ret; i ++ ) {
				_epoll_server_data_header* ph = (_epoll_server_data_header*)(events[i].data.ptr);
				//event
				if ( ph->type == _epoll_server_data_header::TYPE_EVENT ) {
					if ( events[i].events & EPOLLIN ) {
						uint64_t v;
						ssize_t sret = ::read(pItem->evtfd, &v, sizeof(uint64_t));
						(void)sret;
						assert( sret == sizeof(uint64_t) );
						brev = epoll_rev_event(pItem->epfd, pItem->evtfd, &(pItem->evt_data), false);
						assert( brev );
						exit_flag = true;
						break;
					}
					continue;
				}
				if ( __sync_val_compare_and_swap(&pThis->m_iExit, 1, 1) )
					continue;
				//handle
				handle_server_data_base* p = (handle_server_data_base*)((static_cast<_epoll_server_data_full*>(ph))->pv);
				p->iCurrentFlag = 0;
				//timeout
				if ( ph->type == _epoll_server_data_header::TYPE_TIMER ) {
					if ( events[i].events & EPOLLIN )
						next_array[next_count ++] = p;
					continue;
				}
				//IO
				if ( __sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1) )
					continue;
				if ( p->op_type == OP_TYPE_ACCEPT ) {
					pThis->process_accept(events[i].events, p);
				}
				else {
					if ( p->op_type == OP_TYPE_CONNECT ) {
						p->op_type = OP_TYPE_NONE;
						pThis->process_connect(events[i].events, p);
					}
					else {
						if ( !__sync_val_compare_and_swap(&(p->iNextFlag), 1, 1) )
							p->iCurrentFlag = 1;
						//events
						pThis->set_timer(p, true);
						if ( events[i].events & (EPOLLRDHUP | EPOLLHUP) ) {
							p->recv_len = 0;
							pThis->m_util.callback(utilClass::CB_RECV, p, true, pThis);
						}
						else if ( events[i].events & EPOLLERR ) {
							if ( events[i].events & EPOLLIN )
								pThis->m_util.callback(utilClass::CB_RECV, p, false, pThis);
							else
								pThis->m_util.callback(utilClass::CB_SENT, p, false, pThis);
						}
						else {
							if ( events[i].events & EPOLLIN )
								pThis->process_recv(events[i].events, p);
							if ( !__sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1)
								&& (events[i].events & EPOLLOUT) )
								pThis->process_send(events[i].events, p);
						}
					}
					pThis->start_next(p);
				}
			}
			//exit
			if ( exit_flag )
				break;
			//next array
			for ( uint32_t k = 0; k < next_count; k ++ ) {
				handle_server_data_base* p = next_array[k];
				thread_item* pi = (thread_item*)(void*)(p->index);
				//IO has been done
				if ( p->iCurrentFlag != 0 )
					continue;
				//timeout
				if ( !__sync_val_compare_and_swap(&(p->iNextFlag), 1, 1) ) {
					pThis->m_util.callback(utilClass::CB_TIMEOUT, p, false, pThis);
					pThis->start_next(p);
					continue;
				}
				//in next process
				/* acquire */
				while ( __sync_val_compare_and_swap(&(p->iCallFlag), 0, 1) )
					;
				if ( __sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1) ) {
					/* finish */
					__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
					//close
					epoll_del_socket(pi->epfd, p);  //no check
					epoll_del_timer(pi->epfd, p);  //no check
					close_handle(p);
					pThis->m_util.callback(utilClass::CB_CLOSED_BEGIN, p, true, pThis);
					/* wait */
					while ( __sync_val_compare_and_swap(&(p->iCallFlag), 1, 1) )
						;
					__sync_val_compare_and_swap(&(p->iNextFlag), 1, 0);
					pThis->m_util.callback(utilClass::CB_CLOSED_END, p, true, pThis);
					continue;
				}
				//next event
				if ( __sync_add_and_fetch(&(p->send_len), 0) )
					brev = epoll_rev_socket(pi->epfd, p, e_inout, false);
				else
					brev = epoll_rev_socket(pi->epfd, p, e_in, false);
				assert( brev );
				brev = epoll_rev_event(pi->epfd, p->tmfd, p->timer_data.get_header(), false);
				assert( brev );
				pThis->set_timer(p, false);
				__sync_val_compare_and_swap(&(p->iNextFlag), 1, 0);
				/* finish */
				__sync_val_compare_and_swap(&(p->iCallFlag), 1, 0);
			}
		} //end while
		return NULL;
	}

	void process_accept(uint32_t events, handle_server_data_base* pL) noexcept
	{
		if ( (events & EPOLLERR) || (events & EPOLLHUP) )
			return ;
		thread_item* pli = (thread_item*)(void*)(pL->index);
		while ( true ) {
			//accept
			ns_socket sock;
			int code;
			if ( !pL->sock.GetSocket().Accept(sock.GetSocket(), code) ) {
				if ( code == EAGAIN || code == EWOULDBLOCK )
					break;
				return ;
			}
			handle_server_data_base* pA = (handle_server_data_base*)m_util.callback(utilClass::CB_BEGIN_ACCEPT, NULL, true, this);
			if ( pA == NULL )
				continue;
			pA->sock = rv_forward(sock);
			pA->op_type = OP_TYPE_USER;
			pA->send_len = pA->act_sent_len = 0;
			pA->iCloseFlag = 0;
			thread_item* pai = &m_arrPool[fetch_current_turn()];
			while ( pai == pli )
				pai = &m_arrPool[fetch_current_turn()];
			pA->index = (uintptr_t)pai;
			//timer
			bool b = pA->init_timer();
			m_util.callback(utilClass::CB_ACCEPTED, pA, b, this);
			//next
			if ( __sync_val_compare_and_swap(&(pA->iCloseFlag), 1, 1) )
				b = false;
			if ( b ) {
				pA->op_type = OP_TYPE_NONE;
				//to epoll
				b = false;
				if ( epoll_rev_event(pai->epfd, pA->tmfd, pA->timer_data.get_header(), true) ) {
					if ( !epoll_rev_socket(pai->epfd, pA, e_inout, true) )
						epoll_del_timer(pai->epfd, pA);  //no check
					else
						b = true;
				}
			}
			if ( !b ) {
				//close
				close_handle(pA);
				m_util.callback(utilClass::CB_CLOSED_BEGIN, pA, true, this);
				m_util.callback(utilClass::CB_CLOSED_END, pA, true, this);
				continue;
			}
		} //end while
	}
	void process_connect(uint32_t events, handle_server_data_base* p) noexcept
	{
		bool bSucceeded = false;
		if ( events & EPOLLOUT ) {
			int val = 1;
			socklen_t vlen = sizeof(int);
			if ( !p->sock.GetSocket().GetOpt(SO_ERROR, &val, &vlen) )
				bSucceeded = false;
			else if ( val == 0 )
				bSucceeded = true;
			else
				bSucceeded = false;
		}
		//error: (events & EPOLLERR) || (events & EPOLLHUP) || (events & EPOLLRDHUP)
		m_util.callback(utilClass::CB_CONNECTED, p, bSucceeded, this);
	}
	void process_recv(uint32_t events, handle_server_data_base* p) noexcept
	{
		while ( true ) {
			ssize_t act_len = 0;
			if ( !p->sock.GetSocket().Recv(p->recv_buffer, HANDLE_BUFFER_SIZE, act_len) ) {
				if ( errno != EWOULDBLOCK && errno != EAGAIN )
					m_util.callback(utilClass::CB_RECV, p, false, this);
				break;
			}
			p->recv_len = (uint32_t)act_len;
			bool bzero = p->recv_len == 0;
			m_util.callback(utilClass::CB_RECV, p, true, this);
			//close flag
			if ( __sync_val_compare_and_swap(&(p->iCloseFlag), 1, 1) )
				break;
			//zero
			if ( bzero )
				break;
		}
	}
	void process_send(uint32_t events, handle_server_data_base* p) noexcept
	{
		if ( !__sync_add_and_fetch(&(p->send_len), 0) )
			return ;
		while ( true ) {
			ssize_t act_len = 0;
			if ( !p->sock.GetSocket().Send(p->send_buffer + p->act_sent_len, p->send_len - p->act_sent_len, act_len) ) {
				if ( errno != EWOULDBLOCK && errno != EAGAIN )
					m_util.callback(utilClass::CB_SENT, p, false, this);
				break;
			}
			p->act_sent_len += (uint32_t)act_len;
			if ( p->act_sent_len >= p->send_len ) {
				m_util.callback(utilClass::CB_SENT, p, true, this);
				break;
			}
		}
	}

//tools
	static bool init_thread(thread_item& item, void* pv) noexcept
	{
		//event
		item.evtfd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
		if ( item.evtfd == -1 ) //errno
			return false;
		//epoll
		item.epfd = ::epoll_create1(EPOLL_CLOEXEC);
		if ( item.epfd == -1 ) { //errno
			::close(item.evtfd);  //no check
			return false;
		}
		//add event
		if ( !epoll_rev_event(item.epfd, item.evtfd, &(item.evt_data), true) ) {
			::close(item.evtfd);  //no check
			::close(item.epfd);  //no check
			return false;
		}
		//thread
		server_base* pThis = (server_base*)pv;
		__sync_val_compare_and_swap(&pThis->m_iFinish, 1, 0);
		item.pv = pv;
		int res = ::pthread_create(&item.tid, NULL, &worker_thread, &item);
		if ( res != 0 ) { //error number
			::close(item.evtfd);  //no check
			::close(item.epfd);  //no check
			return false;
		}
		//wait
		while ( __sync_val_compare_and_swap(&pThis->m_iFinish, 1, 1) != 1 ) {
			thread_sleep(1);  //1ms
		}
		return true;
	}
	void dump_thread(thread_item& item) noexcept
	{
		//event
		{
			uint64_t v = 5;
			ssize_t sret = ::write(item.evtfd, &v, sizeof(uint64_t));
			(void)sret;  //-1, errno
			assert( sret == sizeof(uint64_t) );
		}
		//join
		int ret = 0;
		(void)ret;
		{
			void* result;
			ret = ::pthread_join(item.tid, &result);
			assert( ret == 0 );
		}
		//event
		ret = ::close(item.evtfd);
		assert( ret == 0 );  //-1, errno
		//epoll
		ret = ::close(item.epfd);
		assert( ret == 0 );  //-1, errno
	}
	void dump_thread_pool_size(uintptr_t size) noexcept
	{
		__sync_val_compare_and_swap(&m_iExit, 0, 1);
		for ( uintptr_t i = 0; i < size; i ++ )
			dump_thread(m_arrPool[i]);
		__sync_val_compare_and_swap(&m_iExit, 1, 0);
	}
	void dump_thread_pool() noexcept
	{
		dump_thread_pool_size(m_arrPool.GetSize());
	}

	uint32_t fetch_current_turn() noexcept
	{
		uint32_t v = __sync_fetch_and_add(&m_uCurrentTurn, 1);
		return v % m_arrPool.GetSize();
	}

	static bool epoll_rev_event(int epfd, int fd, void* p, bool bAdd) noexcept
	{
		struct epoll_event evt;
		::memset(&evt, 0, sizeof(struct epoll_event));
		evt.events = EPOLLET | EPOLLONESHOT | EPOLLIN;
		evt.data.ptr = p;
		int op = bAdd ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
		int ret = ::epoll_ctl(epfd, op, fd, &evt);
		if ( ret == -1 ) //errno
			return false;
		return true;
	}

	static bool epoll_rev_socket(int epfd, handle_server_data_base* p, int type, bool bAdd) noexcept
	{
		struct epoll_event evt;
		::memset(&evt, 0, sizeof(struct epoll_event));
		evt.events = EPOLLET;
		if ( type != e_listen )
			evt.events |= EPOLLONESHOT;
		if ( type == e_listen || type == e_in )
			evt.events |= EPOLLIN;
		else if ( type == e_out )
			evt.events |= EPOLLOUT;
		else
			evt.events |= (EPOLLIN | EPOLLOUT);
		evt.data.ptr = p->socket_data.get_header();
		int op = bAdd ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
		int ret = ::epoll_ctl(epfd, op, p->sock.GetSocket(), &evt);
		if ( ret == -1 ) //errno
			return false;
		return true;
	}

	static bool _epoll_del_file(int epfd, int fd, void* p) noexcept
	{
		struct epoll_event evt;
		::memset(&evt, 0, sizeof(struct epoll_event));
		evt.data.ptr = p;
		int ret = ::epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &evt);
		if ( ret == -1 ) //errno
			return false;
		return true;
	}

	static bool epoll_del_socket(int epfd, handle_server_data_base* p) noexcept
	{
		return _epoll_del_file(epfd, p->sock.GetSocket(), p->socket_data.get_header());
	}
	static bool epoll_del_timer(int epfd, handle_server_data_base* p) noexcept
	{
		return _epoll_del_file(epfd, p->tmfd, p->timer_data.get_header());
	}

	static void _set_ns_timer(handle_server_data_base* p, int64_t sec, int64_t nsec) noexcept
	{
		struct itimerspec ts;
		::memset(&ts, 0, sizeof(struct itimerspec));
		ts.it_value.tv_sec = sec;
		ts.it_value.tv_nsec = nsec;
		int ret = 0;
		(void)ret;
		ret = ::timerfd_settime(p->tmfd, 0, &ts, NULL);
		assert( ret == 0 );  //-1, errno
	}
	void set_timer(handle_server_data_base* p, bool bDisabled) noexcept
	{
		if ( bDisabled )
			_set_ns_timer(p, 0, 0);
		else
			_set_ns_timer(p, m_util.timeout / 1000, (m_util.timeout % 1000) * 1000 * 1000);
	}

	void start_next(handle_server_data_base* p) noexcept
	{
		if ( __sync_val_compare_and_swap(&m_iExit, 1, 1) )
			return ;
		if ( !__sync_val_compare_and_swap(&(p->iNextFlag), 0, 1) ) {
			constexpr const int64_t c_nsec = 1;  //1ns
			thread_item* pi = (thread_item*)(void*)(p->index);
			//timer
			bool brev = epoll_rev_event(pi->epfd, p->tmfd, p->timer_data.get_header(), false);
			(void)brev;
			assert( brev );
			_set_ns_timer(p, 0, c_nsec);
			//busy wait
			struct timespec tc = { 0 };
			struct timespec tc1 = { 0 };
			::clock_gettime(CLOCK_MONOTONIC_RAW, &tc);  //no check
			while ( true ) {
				::clock_gettime(CLOCK_MONOTONIC_RAW, &tc1);  //no check
				int64_t d = 1000 * 1000 * 1000 * (int64_t)(tc1.tv_sec - tc.tv_sec) + (tc1.tv_nsec - tc.tv_nsec);
				if ( d > c_nsec )
					break;
			}
		}
	}

	static void close_handle(handle_server_data_base* p) noexcept
	{
		p->sock.GetSocket().Disable(SHUT_RDWR);  //no check
		p->sock.GetSocket().Close();
	}

private:
	bool is_valid() const noexcept
	{
		return !m_arrPool.IsEmpty();
	}

private:
	volatile int m_iExit;
	volatile int m_iFinish;

	//thread pool
	CTL::PlainArray<thread_item> m_arrPool;
	volatile uint32_t m_uCurrentTurn;

	//utility
	utilClass m_util;
};

////////////////////////////////////////////////////////////////////////////////
